#include "shell.h"
#include "gd32f30x.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "circular_queue.h"

//shell的命令缓冲区
uint8_t shell_data_buff[FINSH_CMD_SIZE + 1];
// 循环队列 管理缓冲区
QueueStruct shell_queue;

// FreeRTOS核心对象
SemaphoreHandle_t uart_rx_sem;       // UART接收同步信号量（二值信号量）
TaskHandle_t shellTaskHandle = NULL; // Shell任务句柄
struct finsh_shell shell;            // Shell核心状态结构体
struct finsh_syscall* _syscall_table_begin = NULL; // 命令表起始指针
struct finsh_syscall* _syscall_table_end = NULL;   // 命令表结束指针
static uint8_t recv_ch;              // USART接收单字节缓存

/**
 * @brief  USART0中断服务函数（GD32标准库中断处理）
 * @note   实现单字节接收、缓存、通知任务
 *         需要一个字节一个字节的 回显命令并判断命令是否结束 所以没有dma
 */
void USART0_IRQHandler(void)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    // 检查USART接收非空中断标志
    if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE) != RESET) {
        // 读取接收数据到recv_ch
        recv_ch = (uint8_t)usart_data_receive(USART0);
        // 写入数据缓存
        QueuePush(&shell_queue, recv_ch);
        // 释放信号量，通知Shell任务有新数据
        xSemaphoreGiveFromISR(uart_rx_sem, &xHigherPriorityTaskWoken);
        // 清除接收中断标志 接受数据的时候 就相当于清除中断了
        // usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
    }
    // 若需调度更高优先级任务，触发中断级调度
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

}

/**
 * @brief  遍历命令表，获取下一个有效命令表项（跳过空项）
 * @param  call: 当前命令表项指针
 * @return 下一个有效命令表项指针
 */
struct finsh_syscall* finsh_syscall_next(struct finsh_syscall* call)
{
    unsigned int* ptr;
    ptr = (unsigned int*)(call + 1);
    while ((*ptr == 0) && ((unsigned int*)ptr < (unsigned int*)_syscall_table_end))
        ptr++;

    return (struct finsh_syscall*)ptr;
}

/**
 * @brief 命令行字符串分割函数（核心功能：解析命令行，提取命令名和参数数组）
 * @param cmd：待分割的原始命令行字符串（如"echo \"hello world\""）
 * @param length：原始命令行字符串的有效长度（避免遍历到字符串末尾外的垃圾数据）
 * @param argv：输出参数，存储分割后的命令名和参数（argv[0]为命令名，后续为参数）
 * @return uint8_t：分割成功的参数总数（argc，包含命令名本身；返回0表示无有效参数）
 * @note 分割规则：
 *       1. 以空格（' '）或制表符（'\t'）作为默认参数分隔符；
 *       2. 支持双引号（"）包裹的带空格参数（如"hello world"视为一个完整参数）；
 *       3. 支持双引号转义（通过\\\"表示参数内的双引号，如"he\\\"llo"解析为he"llo）；
 *       4. 参数个数上限由FINSH_ARG_MAX控制，超出部分直接丢弃。
 */
static int zns_split(char* cmd, uint8_t length, char* argv[FINSH_ARG_MAX])
{
    char* ptr;          // 字符串遍历指针（用于逐字符扫描命令行）
    uint8_t position;   // 当前扫描到的字符位置索引（与ptr同步，用于边界判断）
    uint8_t argc;       // 参数计数器（记录已分割出的参数个数）

    ptr = cmd;          // 初始化指针，从命令行字符串起始位置开始扫描
    position = 0;       // 初始化位置索引为0
    argc = 0;           // 初始化参数计数器为0

    // 主循环：遍历整个命令行字符串，直到扫描到末尾（position >= length）
    while (position < length) {
        /** 第一步：跳过当前位置的空格/制表符（作为参数分隔符） */
        while ((*ptr == ' ' || *ptr == '\t') && position < length) {
            *ptr = '\0';  // 将分隔符替换为字符串结束符'\0'，实现参数分割（让前一个参数独立）
            ptr++;        // 指针向后移动，跳过当前分隔符
            position++;   // 位置索引同步递增
        }

        /** 第二步：检查参数个数是否已达上限，超出则停止分割（避免argv数组越界） */
        if (argc >= FINSH_ARG_MAX) {
            break;
        }

        /** 第三步：再次检查是否已扫描到字符串末尾，避免后续无效操作 */
        if (position >= length) break;

        /** 第四步：判断当前参数是否为"双引号包裹的带空格参数" */
        if (*ptr == '"') {
            ptr++;        // 跳过开头的双引号（不包含在参数内容中）
            position++;   // 位置索引同步递增

            argv[argc] = ptr;  // 记录当前指针位置为当前参数的起始地址
            argc++;            // 参数计数器递增（完成一个参数的起始标记）

            /** 遍历到双引号结束符或字符串末尾，提取带空格的参数内容 */
            while (*ptr != '"' && position < length) {
                // 处理双引号转义：如果遇到\"，跳过转义符\，只保留"
                if (*ptr == '\\') {
                    if (*(ptr + 1) == '"') {  // 确认是\"组合（转义双引号）
                        ptr++;        // 跳过转义符\
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        position++;   // 位置索引同步递增
                    }
                }
                ptr++;        // 指针向后移动，扫描参数内容
                position++;   // 位置索引同步递增
            }

            /** 检查是否因字符串结束而退出循环（未找到结束双引号），避免越界 */
            if (position >= length) break;

            *ptr = '\0';  // 将结束双引号替换为'\0'，标记当前参数结束
            ptr++;        // 指针向后移动，跳过结束双引号
            position++;   // 位置索引同步递增
        }
        /** 第五步：处理普通参数（无双引号包裹，以空格/制表符为分隔符） */
        else {
            argv[argc] = ptr;  // 记录当前指针位置为当前参数的起始地址
            argc++;            // 参数计数器递增

            /** 遍历到下一个分隔符（空格/制表符）或字符串末尾，提取普通参数 */
            while ((*ptr != ' ' && *ptr != '\t') && position < length) {
                ptr++;        // 指针向后移动，扫描参数内容
                position++;   // 位置索引同步递增
            }

            /** 检查是否已扫描到字符串末尾，避免后续无效操作 */
            if (position >= length) break;
        }
    }

    return argc;  // 返回分割成功的参数总数（argc）
}
/**
 * @brief  根据命令名查找对应的命令函数
 */
static cmd_function_t zns_get_cmd(char* cmd, int size)
{
    struct finsh_syscall* index;
    cmd_function_t cmd_func = NULL;

    for (index = _syscall_table_begin; index < _syscall_table_end; index++) {
        if (strncmp(index->name, "__cmd_", 6) != 0) continue;

        if (strncmp(&index->name[6], cmd, size) == 0 && index->name[6 + size] == '\0') {
            cmd_func = (cmd_function_t)index->func;
            break;
        }
    }

    return cmd_func;
}

/**
 * @brief  命令执行内部函数（核心功能：解析命令名、查找对应处理函数并执行）
 * @param  cmd：待执行的原始命令字符串（如"help -v"）
 * @param  length：原始命令字符串的有效长度（避免处理无效字符）
 * @param  retp：输出参数，用于存储命令执行后的返回值（由具体命令函数填充）
 * @return int：执行状态（0表示成功；-1表示失败，如命令名无效、参数解析失败等）
 * @note  函数流程：提取命令名 → 查找对应函数 → 分割参数 → 执行命令 → 返回结果
 */
static int _zns_exec_cmd(char* cmd, uint8_t length, int* retp)
{
    int argc;                     // 命令参数总数
    uint8_t cmd0_size = 0;        // 命令名的长度（从命令开头到第一个分隔符的字符数）
    cmd_function_t cmd_func;      // 命令对应的处理函数指针（通过zns_get_cmd查找）
    char* argv[FINSH_ARG_MAX];    // 存储分割后的命令名和参数（argv[0]为命令名）

    /** 第一步：提取命令名长度（从命令开头到第一个空格/制表符的位置） */
    // 循环条件：当前字符不是空格/制表符，且未超出命令长度
    while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length)
        cmd0_size++;  // 累加命令名长度（直到遇到分隔符或命令结束）

    /** 第二步：检查命令名是否有效（长度为0表示无有效命令名） */
    if (cmd0_size == 0)
        return -1;  // 无有效命令名，返回失败

    /** 第三步：根据命令名查找对应的处理函数 */
    cmd_func = zns_get_cmd(cmd, cmd0_size);  // 传入命令字符串和命令名长度
    if (cmd_func == NULL)                    // 未找到匹配的命令函数
        return -1;  // 命令不存在，返回失败

    /** 第四步：分割命令字符串为参数数组（包含命令名和后续参数） */
    memset(argv, 0x00, sizeof(argv));  // 初始化参数数组（避免残留垃圾数据）
    argc = zns_split(cmd, length, argv);  // 调用分割函数，获取参数总数

    /** 第五步：检查参数分割是否有效（argc为0表示分割失败） */
    if (argc == 0)
        return -1;  // 参数分割失败，返回失败

    /** 第六步：执行命令函数，并将返回值存入retp */
    *retp = cmd_func(argc, argv);  // 调用命令函数（参数为argc和argv）

    return 0;  // 命令执行成功，返回0
}
/**
 * @brief  保存命令到历史记录（过滤空命令/重复命令）
 */
static void shell_save_history(char* cmd, uint8_t length)
{
    // 过滤空命令（长度为0或仅空格）
    if (length == 0) return;
    char* pure_cmd = cmd;
    while (*pure_cmd == ' ' || *pure_cmd == '\t') {
        pure_cmd++;
        length--;
        if (length == 0) return;
    }

    // 过滤与上一条重复的命令（避免连续输入相同命令重复存储）
    if (shell.history_count > 0) {
        char* last_cmd = shell.cmd_history[(shell.current_history + 1) % FINSH_HISTORY_LINES];
        if (strncmp(pure_cmd, last_cmd, length) == 0 && strlen(last_cmd) == length) {
            return;
        }
    }

    // 计算存储索引：未满直接存，满了则移位覆盖最早的命令
    uint8_t next_index;
    if (shell.history_count < FINSH_HISTORY_LINES) {
        next_index = shell.history_count;
        shell.history_count++;
    } else {
        // 移位：覆盖最早的命令（索引0）
        memmove(
            shell.cmd_history[0],
            shell.cmd_history[1],
            (FINSH_HISTORY_LINES - 1) * FINSH_CMD_SIZE
        );
        next_index = FINSH_HISTORY_LINES - 1;
    }

    // 存储命令（确保字符串结束符，避免乱码）
    memset(shell.cmd_history[next_index], 0, FINSH_CMD_SIZE);
    uint8_t copy_len = (length < FINSH_CMD_SIZE - 1) ? length : (FINSH_CMD_SIZE - 1);
    strncpy(shell.cmd_history[next_index], pure_cmd, copy_len);
    shell.cmd_history[next_index][copy_len] = '\0';
    // 当前索引指向最新命令
    shell.current_history = next_index + 1;
}
/**
 * @brief  命令执行外部接口（原逻辑不变）
 */
static int zns_exec(char* cmd, uint8_t length)
{
    int cmd_ret;
    if (length == 0) return -1;
    // 过滤前导空格
    char* pure_cmd = cmd;
    uint8_t pure_length = length;
    while ((pure_length > 0) && (*pure_cmd == ' ' || *pure_cmd == '\t')) {
        pure_cmd++;
        pure_length--;
    }
    // 保存有效命令到历史（核心添加）
    if (pure_length > 0) {
        shell_save_history(pure_cmd, pure_length);
    }
    if (_zns_exec_cmd(pure_cmd, pure_length, &cmd_ret) == 0) {
        return cmd_ret;
    }
    printf("cmd:%s\r\n", pure_cmd);
    printf("command not found...\r\n");
    return -1;
}

/**
 * @brief  计算字符串公共前缀长度（原逻辑不变）
 */
static int str_common(const char* str1, const char* str2)
{
    const char* str = str1;

    while ((*str != 0) && (*str2 != 0) && (*str == *str2)) {
        str++;
        str2++;
    }

    return (str - str1);
}

/**
 * @brief  命令自动补全核心逻辑（当用户输入部分命令并按Tab键时触发，显示匹配命令并补全公共前缀）
 * @param  prefix：用户当前输入的命令前缀字符串（如输入"he"，则prefix指向"he"）
 * @return void：无返回值，直接修改prefix并打印匹配结果到终端
 * @note  补全规则：
 *        1. 若前缀为空（用户直接按Tab），则调用help函数显示所有命令；
 *        2. 否则，遍历所有注册的命令，筛选出以当前前缀开头的命令；
 *        3. 打印所有匹配的命令，并将prefix更新为这些命令的最长公共前缀（实现自动补全）。
 */
static void zns_auto_complete(char* prefix)
{
    int length;               // 临时变量，用于存储两个命令名的公共前缀长度
    int min_length;           // 所有匹配命令的最长公共前缀长度（用于最终补全）
    const char* name_ptr;     // 指向第一个匹配的命令名（作为计算公共前缀的基准）
    const char* cmd_name;     // 指向当前遍历到的命令的实际名称（去除__cmd_前缀后）
    struct finsh_syscall* index;  // 命令表遍历指针（用于遍历所有注册的命令）

    min_length = 0;           // 初始化最长公共前缀长度为0
    name_ptr = NULL;          // 初始化第一个匹配命令的指针为NULL

    /** 特殊情况：若用户输入的前缀为空（直接按Tab），则显示所有命令（调用help函数） */
    if (*prefix == '\0') {
        help(0, NULL);  // 显示所有可用命令（复用help命令的逻辑）
        return;
    }

    /** 核心逻辑：遍历命令表，筛选出以当前前缀开头的命令 */
    {
        // 遍历命令表（从起始地址到结束地址，通过FINSH_NEXT_SYSCALL宏安全步进）
        for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index)) {
            // 过滤非命令表项（仅处理以"__cmd_"为前缀的表项，这是注册命令的标识）
            if (strncmp(index->name, "__cmd_", 6) != 0)
                continue;

            // 提取命令的实际名称（去除"__cmd_"前缀，如"__cmd_help"→"help"）
            cmd_name = (const char*)&index->name[6];

            // 检查当前命令名是否以用户输入的前缀开头（匹配判断）
            if (strncmp(prefix, cmd_name, strlen(prefix)) == 0) {
                // 若为第一个匹配的命令，初始化基准命令名和公共前缀长度
                if (min_length == 0) {
                    name_ptr = cmd_name;                  // 记录第一个匹配的命令名
                    min_length = strlen(name_ptr);        // 初始公共前缀长度为第一个命令的长度
                }

                // 计算当前匹配命令与基准命令的公共前缀长度
                length = str_common(name_ptr, cmd_name);
                // 更新最长公共前缀长度（取较小值，确保是所有匹配命令的公共部分）
                if (length < min_length)
                    min_length = length;

                // 打印当前匹配的命令（供用户选择）
                printf("%s\r\n", cmd_name);
            }
        }
    }

    /** 若存在匹配的命令，用最长公共前缀补全用户输入的prefix */
    if (name_ptr != NULL) {
        // 将prefix更新为最长公共前缀（长度为min_length）
        strncpy(prefix, name_ptr, min_length);
    }

    return;
}

/**
 * @brief  自动补全终端显示处理
 */
static void shell_auto_complete(char* prefix)
{
    printf("\r\n");
    zns_auto_complete(prefix);
    printf("%s", FINSH_PROMPT);
    printf("%s", prefix);
}


/**
 * @brief  Shell主任务（FreeRTOS原生任务格式，原逻辑不变）
 * @param  argument: 任务参数（未使用）
 */
void shellTask(void* argument)
{
    shell.history_count = 0;    // 初始历史记录数为0
    shell.current_history = 0;  // 初始索引指向0
    memset(shell.cmd_history, 0, sizeof(shell.cmd_history));
    for (;;) {
        // 等待信号量（替代原osSemaphoreWait，无限等待）
        if (xSemaphoreTake(uart_rx_sem, portMAX_DELAY) == pdTRUE) {
            // 循环读取缓存中所有数据（复用原有缓存读取逻辑）
            while (shell_queue.curNum > 0) {
                // 从缓存读取数据到shell.recv_data
                QueuePop(&shell_queue, &shell.recv_data);
                // /* 特殊键处理（上下左右键）*/
                if (shell.recv_data == 0x1b) {
                    shell.stat = WAIT_SPEC_KEY;
                    continue;
                } else if (shell.stat == WAIT_SPEC_KEY) {
                    if (shell.recv_data == 0x5b) {
                        shell.stat = WAIT_FUNC_KEY;
                        continue;
                    }
                    shell.stat = WAIT_NORMAL;
                } else if (shell.stat == WAIT_FUNC_KEY) {
                    shell.stat = WAIT_NORMAL;
                    if (shell.recv_data == 0x41) { /* 上键：切换到更早的命令（数组索引递增） */
                        if (shell.history_count == 0) continue;
                        // 清空当前行并回行首
                        printf("\33[2K\33[1G");
                        // 修正：避免无符号下溢的索引调整
                        if (shell.current_history > 0) {
                            shell.current_history--;
                        } else {
                            shell.current_history = shell.history_count - 1;
                        }
                        // 加载并显示命令
                        memset(shell.line, 0, sizeof(shell.line));
                        strcpy((char*)shell.line, shell.cmd_history[shell.current_history]);
                        shell.line_position = strlen((const char*)shell.line);
                        shell.line_curpos = shell.line_position;
                        printf("%s%s", FINSH_PROMPT, shell.line);
                        continue;
                    } else if (shell.recv_data == 0x42) { /* 下键：切换到更新的命令（数组索引递减） */
                        if (shell.history_count == 0) continue;
                        // 清空当前行并回行首
                        printf("\33[2K\33[1G");
                        // 调整索引：向前切换到更新的命令
                        shell.current_history++;
                        // 边界处理：如果超过最新命令位置，清空输入（显示空命令）
                        if (shell.current_history >= shell.history_count) {
                            shell.current_history = shell.history_count;  // 保持在最新位置外侧
                            memset(shell.line, 0, sizeof(shell.line));
                            shell.line_position = 0;
                            shell.line_curpos = 0;
                        } else {
                            // 加载并显示下一条命令
                            strcpy((char*)shell.line, shell.cmd_history[shell.current_history]);
                            shell.line_position = strlen((const char*)shell.line);
                            shell.line_curpos = shell.line_position;
                        }
                        printf("%s%s", FINSH_PROMPT, shell.line);
                        continue;
                    } else if (shell.recv_data == 0x44) { /* 左键：光标左移 */
                        if (shell.line_curpos > 0) {  // 光标不在最左侧
                            shell.line_curpos--;  // 光标位置减1
                            printf("\b");  // 终端显示：光标左移一格
                        }
                        continue;
                    } else if (shell.recv_data == 0x43) { /* 右键：光标右移 */
                        if (shell.line_curpos < shell.line_position) {  // 光标不在最右侧
                            // 终端显示：打印当前光标位置的下一个字符（模拟光标右移）
                            printf("%c", shell.line[shell.line_curpos]);
                            shell.line_curpos++;  // 光标位置加1
                        }
                        continue;
                    }
                }

                /* 无效字符过滤 */
                if (shell.recv_data == '\0' || shell.recv_data == 0xFF) continue;
                /* Tab键自动补全 */
                else if (shell.recv_data == '\t') {
                    int i;
                    for (i = 0; i < shell.line_curpos; i++)
                        printf("\b");
                    shell_auto_complete((char*)&shell.line[0]);
                    shell.line_curpos = shell.line_position = strlen((const char*)shell.line);
                    continue;
                }

                /* 退格键处理 */
                else if (shell.recv_data == 0x7f || shell.recv_data == 0x08) {
                    if (shell.line_curpos == 0)
                        continue;
                    shell.line_position--;
                    shell.line_curpos--;

                    if (shell.line_position > shell.line_curpos) {
                        int i;
                        memmove(&shell.line[shell.line_curpos],
                            &shell.line[shell.line_curpos + 1],
                            shell.line_position - shell.line_curpos);
                        shell.line[shell.line_position] = 0;
                        printf("\b%s  \b", &shell.line[shell.line_curpos]);
                        for (i = shell.line_curpos; i <= shell.line_position; i++)
                            printf("\b");
                    } else {
                        printf("\b \b");
                        shell.line[shell.line_position] = 0;
                    }
                    continue;
                }

                /* 回车/换行执行命令 */
                if (shell.recv_data == '\r' || shell.recv_data == '\n') {
#if SHELL_ECHO_MODE == 1
                    printf("\r\n");
#endif
                    zns_exec((char*)shell.line, shell.line_position);
                    printf(FINSH_PROMPT);
                    memset(shell.line, 0, sizeof(shell.line));
                    shell.line_curpos = shell.line_position = 0;
                    continue;
                }

                /* 命令行长度超限重置 */
                if (shell.line_position >= FINSH_CMD_SIZE)
                    shell.line_position = 0;

                /* 普通字符处理 */
                if (shell.line_curpos < shell.line_position) {
                    int i;
                    memmove(&shell.line[shell.line_curpos + 1],
                        &shell.line[shell.line_curpos],
                        shell.line_position - shell.line_curpos);
                    shell.line[shell.line_curpos] = shell.recv_data;
#if SHELL_ECHO_MODE == 1
                    printf("%s", &shell.line[shell.line_curpos]);
#endif
                    for (i = shell.line_curpos; i < shell.line_position; i++)
                        printf("\b");
                } else {
                    shell.line[shell.line_position] = shell.recv_data;
#if SHELL_ECHO_MODE == 1
                    printf("%c", shell.recv_data);
#endif
                }

                /* 更新状态 */
                shell.recv_data = 0;
                shell.line_position++;
                shell.line_curpos++;
                if (shell.line_position >= FINSH_CMD_SIZE) {
                    shell.line_position = 0;
                    shell.line_curpos = 0;
                }
            }
        }
    }
}

/**
 * @brief  初始化命令表
 */
static void finsh_system_function_init(const void* begin, const void* end)
{
    _syscall_table_begin = (struct finsh_syscall*)begin;
    _syscall_table_end = (struct finsh_syscall*)end;
}

/**
 * @brief  Shell版本标题点阵数据
 */
const unsigned char head[11][16] =
{
       {0x00,0x00,0x00,0x7E,0x06,0x04,0x0C,0x08,0x10,0x30,0x20,0x60,0x7E,0x7E,0x00,0x00},/*"Z",0*/
       {0x00,0x00,0x00,0x42,0x62,0x62,0x72,0x52,0x5A,0x4A,0x4E,0x46,0x46,0x46,0x00,0x00},/*"N",1*/
       {0x00,0x00,0x00,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",2*/
       {0x00,0x00,0x00,0x3C,0x66,0x46,0x60,0x30,0x1C,0x06,0x42,0x42,0x66,0x3C,0x00,0x00},/*"S",3*/
       {0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x5E,0x62,0x42,0x42,0x42,0x42,0x42,0x00,0x00},/*"h",4*/
       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x46,0x7E,0x40,0x42,0x66,0x1C,0x00,0x00},/*"e",5*/
       {0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00},/*"l",6*/
       {0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00},/*"l",7*/
};

/**
 * @brief  显示Shell版本信息（原逻辑不变）
 */
void show_version(void)
{
    unsigned char i = 0, j = 0, k = 0;

    for (k = 0; k < 16; k++) {
        printf(" ");
        for (j = 0; j < 11; j++) {
            for (i = 0; i < 8; i++) {
                if (head[j][k] & (0X80 >> i))
                    printf("%c", "AR'Shell"[j]);
                else
                    printf(" ");
            }
        }
        printf(" \r\n");
    }
}


/**
 * @brief  Shell初始化（GD32+FreeRTOS适配，替换原CMSIS-OS初始化）
 */
void shell_init(void)
{
    // 显示版本信息
    show_version();
    // 初始化数据缓存（复用原有缓存模块）
    QueueInit(&shell_queue, shell_data_buff, FINSH_CMD_SIZE + 1);
    // 初始化Shell状态
    shell.stat = WAIT_NORMAL;
    // 初始化命令表（链接器生成的FSymTab段边界）
    finsh_system_function_init(&FSymTab$$Base, &FSymTab$$Limit);
    // 创建FreeRTOS二值信号量（用于中断-任务同步）
    uart_rx_sem = xSemaphoreCreateBinary();
    configASSERT(uart_rx_sem != NULL); // 检查信号量创建成功

    // 创建Shell任务（FreeRTOS原生API）
    xTaskCreate(
        shellTask,                  // 任务函数
        "shell_Task",                // 任务名称
        SHELL_TASK_STACK_SIZE,                        // 栈大小（字）
        NULL,                       // 任务参数
        SHELL_TASK_PRIORITY,                          // 优先级（高于空闲优先级）
        &shellTaskHandle            // 任务句柄
    );
    configASSERT(shellTaskHandle != NULL); // 检查任务创建成功
    // 打印任务创建状态（原逻辑保留）
    printf(FINSH_PROMPT);
}
